mmu_update fixes for x86_64. About halfway there.
Signed-off-by: keir.fraser@cl.cam.ac.uk
cpuid
bt $29,%edx # Long mode feature?
jnc bad_cpu
+ mov %edx,%edi
skip_boot_checks:
/* Set up FPU. */
/* Set up EFER (Extended Feature Enable Register). */
movl $MSR_EFER, %ecx
rdmsr
- /* Long Mode, SYSCALL/SYSRET, No-Execute */
- movl $(EFER_LME|EFER_SCE|EFER_NX),%eax
- wrmsr
+ btsl $_EFER_LME,%eax /* Long Mode */
+ btsl $_EFER_SCE,%eax /* SYSCALL/SYSRET */
+ btl $20,%edi /* CPUID 0x80000001, EDX[20] */
+ jnc 1f
+ btsl $_EFER_NX,%eax /* No-Execute */
+1: wrmsr
mov $0x80050033,%eax /* hi-to-lo: PG,AM,WP,NE,ET,MP,PE */
mov %eax,%cr0
/*
- * We allow an L2 tables to map each other (a.k.a. linear page tables). It
- * needs some special care with reference counst and access permissions:
+ * We allow root tables to map each other (a.k.a. linear page tables). It
+ * needs some special care with reference counts and access permissions:
* 1. The mapping entry must be read-only, or the guest may get write access
* to its own PTEs.
* 2. We must only bump the reference counts for an *already validated*
* L2 table, or we can end up in a deadlock in get_page_type() by waiting
* on a validation that is required to complete that validation.
* 3. We only need to increment the reference counts for the mapped page
- * frame if it is mapped by a different L2 table. This is sufficient and
- * also necessary to allow validation of an L2 table mapping itself.
+ * frame if it is mapped by a different root table. This is sufficient and
+ * also necessary to allow validation of a root table mapping itself.
*/
static int
get_linear_pagetable(
- l2_pgentry_t l2e, unsigned long pfn, struct domain *d)
+ root_pgentry_t re, unsigned long re_pfn, struct domain *d)
{
u32 x, y;
struct pfn_info *page;
+ unsigned long pfn;
- if ( (l2_pgentry_val(l2e) & _PAGE_RW) )
+ if ( (root_pgentry_val(re) & _PAGE_RW) )
{
MEM_LOG("Attempt to create linear p.t. with write perms");
return 0;
}
- if ( (l2_pgentry_val(l2e) >> PAGE_SHIFT) != pfn )
+ if ( (pfn = root_pgentry_to_pfn(re)) != re_pfn )
{
/* Make sure the mapped frame belongs to the correct domain. */
- if ( unlikely(!get_page_from_pagenr(l2_pgentry_to_pfn(l2e), d)) )
+ if ( unlikely(!get_page_from_pagenr(pfn, d)) )
return 0;
/*
* Make sure that the mapped frame is an already-validated L2 table.
* If so, atomically increment the count (checking for overflow).
*/
- page = &frame_table[l2_pgentry_to_pfn(l2e)];
+ page = &frame_table[pfn];
y = page->u.inuse.type_info;
do {
x = y;
if ( unlikely((x & PGT_count_mask) == PGT_count_mask) ||
unlikely((x & (PGT_type_mask|PGT_validated)) !=
- (PGT_l2_page_table|PGT_validated)) )
+ (PGT_root_page_table|PGT_validated)) )
{
put_page(page);
return 0;
if ( !(l1v & _PAGE_PRESENT) )
return 1;
- if ( unlikely(l1v & (_PAGE_GLOBAL|_PAGE_PAT)) )
+ if ( unlikely(l1v & L1_DISALLOW_MASK) )
{
- MEM_LOG("Bad L1 type settings %04lx", l1v & (_PAGE_GLOBAL|_PAGE_PAT));
+ MEM_LOG("Bad L1 type settings %04lx", l1v & L1_DISALLOW_MASK);
return 0;
}
if ( !(l2_pgentry_val(l2e) & _PAGE_PRESENT) )
return 1;
- if ( unlikely((l2_pgentry_val(l2e) & (_PAGE_GLOBAL|_PAGE_PSE))) )
+ if ( unlikely((l2_pgentry_val(l2e) & L2_DISALLOW_MASK)) )
{
MEM_LOG("Bad L2 page type settings %04lx",
- l2_pgentry_val(l2e) & (_PAGE_GLOBAL|_PAGE_PSE));
+ l2_pgentry_val(l2e) & L2_DISALLOW_MASK);
return 0;
}
l2_pgentry_to_pfn(l2e),
PGT_l1_page_table | (va_idx<<PGT_va_shift), d);
+#if defined(__i386__)
+ return rc ? rc : get_linear_pagetable(l2e, pfn, d);
+#elif defined(__x86_64__)
+ return rc;
+#endif
+}
+
+
+#ifdef __x86_64__
+
+static int
+get_page_from_l3e(
+ l3_pgentry_t l3e, unsigned long pfn, struct domain *d)
+{
+ if ( !(l3_pgentry_val(l3e) & _PAGE_PRESENT) )
+ return 1;
+
+ if ( unlikely((l3_pgentry_val(l3e) & L3_DISALLOW_MASK)) )
+ {
+ MEM_LOG("Bad L3 page type settings %04lx",
+ l3_pgentry_val(l3e) & L3_DISALLOW_MASK);
+ return 0;
+ }
+
+ return get_page_and_type_from_pagenr(
+ l3_pgentry_to_pfn(l3e), PGT_l3_page_table, d);
+}
+
+
+static int
+get_page_from_l4e(
+ l4_pgentry_t l4e, unsigned long pfn, struct domain *d)
+{
+ int rc;
+
+ if ( !(l4_pgentry_val(l4e) & _PAGE_PRESENT) )
+ return 1;
+
+ if ( unlikely((l4_pgentry_val(l4e) & L4_DISALLOW_MASK)) )
+ {
+ MEM_LOG("Bad L4 page type settings %04lx",
+ l4_pgentry_val(l4e) & L4_DISALLOW_MASK);
+ return 0;
+ }
+
+ rc = get_page_and_type_from_pagenr(
+ l4_pgentry_to_pfn(l4e), PGT_l4_page_table, d);
+
if ( unlikely(!rc) )
- return get_linear_pagetable(l2e, pfn, d);
+ return get_linear_pagetable(l4e, pfn, d);
return 1;
}
+#endif /* __x86_64__ */
+
static void put_page_from_l1e(l1_pgentry_t l1e, struct domain *d)
{
}
+#ifdef __x86_64__
+
+static void put_page_from_l3e(l3_pgentry_t l3e, unsigned long pfn)
+{
+ if ( (l3_pgentry_val(l3e) & _PAGE_PRESENT) &&
+ ((l3_pgentry_val(l3e) >> PAGE_SHIFT) != pfn) )
+ put_page_and_type(&frame_table[l3_pgentry_to_pfn(l3e)]);
+}
+
+
+static void put_page_from_l4e(l4_pgentry_t l4e, unsigned long pfn)
+{
+ if ( (l4_pgentry_val(l4e) & _PAGE_PRESENT) &&
+ ((l4_pgentry_val(l4e) >> PAGE_SHIFT) != pfn) )
+ put_page_and_type(&frame_table[l4_pgentry_to_pfn(l4e)]);
+}
+
+#endif /* __x86_64__ */
+
+
+static int alloc_l1_table(struct pfn_info *page)
+{
+ struct domain *d = page_get_owner(page);
+ unsigned long pfn = page_to_pfn(page);
+ l1_pgentry_t *pl1e;
+ int i;
+
+ pl1e = map_domain_mem(pfn << PAGE_SHIFT);
+
+ for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
+ if ( unlikely(!get_page_from_l1e(pl1e[i], d)) )
+ goto fail;
+
+ unmap_domain_mem(pl1e);
+ return 1;
+
+ fail:
+ while ( i-- > 0 )
+ put_page_from_l1e(pl1e[i], d);
+
+ unmap_domain_mem(pl1e);
+ return 0;
+}
+
+
static int alloc_l2_table(struct pfn_info *page)
{
struct domain *d = page_get_owner(page);
- unsigned long page_nr = page_to_pfn(page);
+ unsigned long pfn = page_to_pfn(page);
l2_pgentry_t *pl2e;
int i;
- pl2e = map_domain_mem(page_nr << PAGE_SHIFT);
+ pl2e = map_domain_mem(pfn << PAGE_SHIFT);
for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
- if ( unlikely(!get_page_from_l2e(pl2e[i], page_nr, d, i)) )
+ if ( unlikely(!get_page_from_l2e(pl2e[i], pfn, d, i)) )
goto fail;
#if defined(__i386__)
&idle_pg_table[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
HYPERVISOR_ENTRIES_PER_L2_PAGETABLE * sizeof(l2_pgentry_t));
pl2e[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
- mk_l2_pgentry((page_nr << PAGE_SHIFT) | __PAGE_HYPERVISOR);
+ mk_l2_pgentry((pfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
pl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] =
mk_l2_pgentry(__pa(page_get_owner(page)->arch.mm_perdomain_pt) |
__PAGE_HYPERVISOR);
fail:
while ( i-- > 0 )
- put_page_from_l2e(pl2e[i], page_nr);
+ put_page_from_l2e(pl2e[i], pfn);
unmap_domain_mem(pl2e);
return 0;
}
-static int alloc_l1_table(struct pfn_info *page)
+#ifdef __x86_64__
+
+static int alloc_l3_table(struct pfn_info *page)
{
struct domain *d = page_get_owner(page);
- unsigned long page_nr = page_to_pfn(page);
- l1_pgentry_t *pl1e;
+ unsigned long pfn = page_to_pfn(page);
+ l3_pgentry_t *pl3e = page_to_virt(page);
int i;
- pl1e = map_domain_mem(page_nr << PAGE_SHIFT);
-
- for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
- if ( unlikely(!get_page_from_l1e(pl1e[i], d)) )
+ for ( i = 0; i < L3_PAGETABLE_ENTRIES; i++ )
+ if ( unlikely(!get_page_from_l3e(pl3e[i], pfn, d)) )
goto fail;
- unmap_domain_mem(pl1e);
return 1;
fail:
while ( i-- > 0 )
- put_page_from_l1e(pl1e[i], d);
+ put_page_from_l3e(pl3e[i], pfn);
- unmap_domain_mem(pl1e);
return 0;
}
-static void free_l2_table(struct pfn_info *page)
+static int alloc_l4_table(struct pfn_info *page)
{
- unsigned long page_nr = page - frame_table;
- l2_pgentry_t *pl2e;
- int i;
+ struct domain *d = page_get_owner(page);
+ unsigned long pfn = page_to_pfn(page);
+ l4_pgentry_t *pl4e = page_to_virt(page);
+ int i;
- pl2e = map_domain_mem(page_nr << PAGE_SHIFT);
+ for ( i = 0; i < L4_PAGETABLE_ENTRIES; i++ )
+ if ( unlikely(!get_page_from_l4e(pl4e[i], pfn, d)) )
+ goto fail;
- for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
- put_page_from_l2e(pl2e[i], page_nr);
+ return 1;
- unmap_domain_mem(pl2e);
+ fail:
+ while ( i-- > 0 )
+ put_page_from_l4e(pl4e[i], pfn);
+
+ return 0;
}
+#endif /* __x86_64__ */
+
static void free_l1_table(struct pfn_info *page)
{
struct domain *d = page_get_owner(page);
- unsigned long page_nr = page - frame_table;
+ unsigned long pfn = page_to_pfn(page);
l1_pgentry_t *pl1e;
int i;
- pl1e = map_domain_mem(page_nr << PAGE_SHIFT);
+ pl1e = map_domain_mem(pfn << PAGE_SHIFT);
for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
put_page_from_l1e(pl1e[i], d);
}
+static void free_l2_table(struct pfn_info *page)
+{
+ unsigned long pfn = page_to_pfn(page);
+ l2_pgentry_t *pl2e;
+ int i;
+
+ pl2e = map_domain_mem(pfn << PAGE_SHIFT);
+
+ for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
+ put_page_from_l2e(pl2e[i], pfn);
+
+ unmap_domain_mem(pl2e);
+}
+
+
+#ifdef __x86_64__
+
+static void free_l3_table(struct pfn_info *page)
+{
+ unsigned long pfn = page_to_pfn(page);
+ l3_pgentry_t *pl3e = page_to_virt(page);
+ int i;
+
+ for ( i = 0; i < L3_PAGETABLE_ENTRIES; i++ )
+ put_page_from_l3e(pl3e[i], pfn);
+}
+
+
+static void free_l4_table(struct pfn_info *page)
+{
+ unsigned long pfn = page_to_pfn(page);
+ l4_pgentry_t *pl4e = page_to_virt(page);
+ int i;
+
+ for ( i = 0; i < L4_PAGETABLE_ENTRIES; i++ )
+ put_page_from_l4e(pl4e[i], pfn);
+}
+
+#endif /* __x86_64__ */
+
+
static inline int update_l2e(l2_pgentry_t *pl2e,
l2_pgentry_t ol2e,
l2_pgentry_t nl2e)
return alloc_l1_table(page);
case PGT_l2_page_table:
return alloc_l2_table(page);
+#ifdef __x86_64__
+ case PGT_l3_page_table:
+ return alloc_l3_table(page);
+ case PGT_l4_page_table:
+ return alloc_l4_table(page);
+#endif
case PGT_gdt_page:
case PGT_ldt_page:
return alloc_segdesc_page(page);
free_l2_table(page);
break;
+#ifdef __x86_64__
+ case PGT_l3_page_table:
+ free_l3_table(page);
+ break;
+
+ case PGT_l4_page_table:
+ free_l4_table(page);
+ break;
+#endif
+
default:
BUG();
}
* circumstances should be very rare.
*/
struct domain *d = page_get_owner(page);
- if ( unlikely(NEED_FLUSH(tlbflush_time[d->exec_domain[0]->processor],
+ if ( unlikely(NEED_FLUSH(tlbflush_time[d->exec_domain[0]->
+ processor],
page->tlbflush_timestamp)) )
{
perfc_incr(need_flush_tlb_flush);
/* Don't duplicate feature flags which are redundant with Intel! */
#define X86_FEATURE_SYSCALL (1*32+11) /* SYSCALL/SYSRET */
#define X86_FEATURE_MP (1*32+19) /* MP Capable. */
+#define X86_FEATURE_NX (1*32+20) /* No-Execute Bit. */
#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */
#define X86_FEATURE_LM (1*32+29) /* Long Mode (x86-64) */
#define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow! extensions */
#define cpu_has_xmm boot_cpu_has(X86_FEATURE_XMM)
#define cpu_has_ht boot_cpu_has(X86_FEATURE_HT)
#define cpu_has_mp boot_cpu_has(X86_FEATURE_MP)
+#define cpu_has_nx boot_cpu_has(X86_FEATURE_NX)
#define cpu_has_k6_mtrr boot_cpu_has(X86_FEATURE_K6_MTRR)
#define cpu_has_cyrix_arr boot_cpu_has(X86_FEATURE_CYRIX_ARR)
#define cpu_has_centaur_mcr boot_cpu_has(X86_FEATURE_CENTAUR_MCR)
/* Page-table type. */
#ifndef __ASSEMBLY__
typedef struct { unsigned long pt_lo; } pagetable_t;
-#define pagetable_val(_x) ((_x).pt_lo)
-#define mk_pagetable(_x) ( (pagetable_t) { (_x) } )
+#define pagetable_val(_x) ((_x).pt_lo)
+#define mk_pagetable(_x) ( (pagetable_t) { (_x) } )
#endif
#ifndef __ASSEMBLY__
-#define PAGE_SIZE (1UL << PAGE_SHIFT)
+#define PAGE_SIZE (1UL << PAGE_SHIFT)
#else
-#define PAGE_SIZE (1 << PAGE_SHIFT)
+#define PAGE_SIZE (1 << PAGE_SHIFT)
#endif
-#define PAGE_MASK (~(PAGE_SIZE-1))
+#define PAGE_MASK (~(PAGE_SIZE-1))
-#define clear_page(_p) memset((void *)(_p), 0, PAGE_SIZE)
-#define copy_page(_t,_f) memcpy((void *)(_t), (void *)(_f), PAGE_SIZE)
+#define clear_page(_p) memset((void *)(_p), 0, PAGE_SIZE)
+#define copy_page(_t,_f) memcpy((void *)(_t), (void *)(_f), PAGE_SIZE)
-#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
-#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
-#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
-#define pfn_to_page(_pfn) (frame_table + (_pfn))
-#define phys_to_page(kaddr) (frame_table + ((kaddr) >> PAGE_SHIFT))
-#define virt_to_page(kaddr) (frame_table + (__pa(kaddr) >> PAGE_SHIFT))
-#define VALID_PAGE(page) ((page - frame_table) < max_mapnr)
+#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
+#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
+#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
+#define pfn_to_page(_pfn) (frame_table + (_pfn))
+#define phys_to_page(kaddr) (frame_table + ((kaddr) >> PAGE_SHIFT))
+#define virt_to_page(kaddr) (frame_table + (__pa(kaddr) >> PAGE_SHIFT))
+#define VALID_PAGE(page) ((page - frame_table) < max_mapnr)
/*
* NB. We don't currently track I/O holes in the physical RAM space.
* For now we guess that I/O devices will be mapped in the first 1MB
* (e.g., VGA buffers) or beyond the end of physical RAM.
*/
-#define pfn_is_ram(_pfn) (((_pfn) > 0x100) && ((_pfn) < max_page))
+#define pfn_is_ram(_pfn) (((_pfn) > 0x100) && ((_pfn) < max_page))
/* High table entries are reserved by the hypervisor. */
-#define DOMAIN_ENTRIES_PER_L2_PAGETABLE \
+#define DOMAIN_ENTRIES_PER_L2_PAGETABLE \
(HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT)
#define HYPERVISOR_ENTRIES_PER_L2_PAGETABLE \
(L2_PAGETABLE_ENTRIES - DOMAIN_ENTRIES_PER_L2_PAGETABLE)
/* Flush global pages as well. */
#define __pge_off() \
- do { \
- __asm__ __volatile__( \
- "mov %0, %%cr4; # turn off PGE " \
- :: "r" (mmu_cr4_features & ~X86_CR4_PGE)); \
- } while (0)
+ do { \
+ __asm__ __volatile__( \
+ "mov %0, %%cr4; # turn off PGE " \
+ : : "r" (mmu_cr4_features & ~X86_CR4_PGE) ); \
+ } while ( 0 )
#define __pge_on() \
- do { \
- __asm__ __volatile__( \
- "mov %0, %%cr4; # turn off PGE " \
- :: "r" (mmu_cr4_features)); \
- } while (0)
+ do { \
+ __asm__ __volatile__( \
+ "mov %0, %%cr4; # turn off PGE " \
+ : : "r" (mmu_cr4_features) ); \
+ } while ( 0 )
-#define __flush_tlb_pge() \
- do { \
- __pge_off(); \
- __flush_tlb(); \
- __pge_on(); \
- } while (0)
+#define __flush_tlb_pge() \
+ do { \
+ __pge_off(); \
+ __flush_tlb(); \
+ __pge_on(); \
+ } while ( 0 )
#define __flush_tlb_one(__addr) \
-__asm__ __volatile__("invlpg %0": :"m" (*(char *) (__addr)))
+ __asm__ __volatile__("invlpg %0": :"m" (*(char *) (__addr)))
#endif /* !__ASSEMBLY__ */
-#define _PAGE_PRESENT 0x001
-#define _PAGE_RW 0x002
-#define _PAGE_USER 0x004
-#define _PAGE_PWT 0x008
-#define _PAGE_PCD 0x010
-#define _PAGE_ACCESSED 0x020
-#define _PAGE_DIRTY 0x040
-#define _PAGE_PAT 0x080
-#define _PAGE_PSE 0x080
-#define _PAGE_GLOBAL 0x100
+#define _PAGE_PRESENT 0x001UL
+#define _PAGE_RW 0x002UL
+#define _PAGE_USER 0x004UL
+#define _PAGE_PWT 0x008UL
+#define _PAGE_PCD 0x010UL
+#define _PAGE_ACCESSED 0x020UL
+#define _PAGE_DIRTY 0x040UL
+#define _PAGE_PAT 0x080UL
+#define _PAGE_PSE 0x080UL
+#define _PAGE_GLOBAL 0x100UL
#define __PAGE_HYPERVISOR \
- (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
#define __PAGE_HYPERVISOR_NOCACHE \
- (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED)
+ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED)
#define MAKE_GLOBAL(_x) ((_x) | _PAGE_GLOBAL)
#endif /* !__ASSEMBLY__ */
/* Strip type from a table entry. */
-#define l1_pgentry_val(_x) ((_x).l1_lo)
-#define l2_pgentry_val(_x) ((_x).l2_lo)
+#define l1_pgentry_val(_x) ((_x).l1_lo)
+#define l2_pgentry_val(_x) ((_x).l2_lo)
+#define root_pgentry_val(_x) (l2_pgentry_val(_x))
/* Add type to a table entry. */
-#define mk_l1_pgentry(_x) ( (l1_pgentry_t) { (_x) } )
-#define mk_l2_pgentry(_x) ( (l2_pgentry_t) { (_x) } )
+#define mk_l1_pgentry(_x) ( (l1_pgentry_t) { (_x) } )
+#define mk_l2_pgentry(_x) ( (l2_pgentry_t) { (_x) } )
+#define mk_root_pgentry(_x) (mk_l2_pgentry(_x))
/* Turn a typed table entry into a physical address. */
-#define l1_pgentry_to_phys(_x) (l1_pgentry_val(_x) & PAGE_MASK)
-#define l2_pgentry_to_phys(_x) (l2_pgentry_val(_x) & PAGE_MASK)
+#define l1_pgentry_to_phys(_x) (l1_pgentry_val(_x) & PAGE_MASK)
+#define l2_pgentry_to_phys(_x) (l2_pgentry_val(_x) & PAGE_MASK)
+#define root_pgentry_to_phys(_x) (l2_pgentry_to_phys(_x))
/* Turn a typed table entry into a page index. */
-#define l1_pgentry_to_pfn(_x) (l1_pgentry_val(_x) >> PAGE_SHIFT)
-#define l2_pgentry_to_pfn(_x) (l2_pgentry_val(_x) >> PAGE_SHIFT)
+#define l1_pgentry_to_pfn(_x) (l1_pgentry_val(_x) >> PAGE_SHIFT)
+#define l2_pgentry_to_pfn(_x) (l2_pgentry_val(_x) >> PAGE_SHIFT)
+#define root_pgentry_to_pfn(_x) (l2_pgentry_to_pfn(_x))
/* Pagetable walking. */
#define l2_pgentry_to_l1(_x) \
/* Given a virtual address, get an entry offset into a linear page table. */
#define l1_linear_offset(_a) ((_a) >> PAGE_SHIFT)
+#define PGT_root_page_table PGT_l2_page_table
+
+#define _PAGE_NX 0UL
+
+#define L1_DISALLOW_MASK (3UL << 7)
+#define L2_DISALLOW_MASK (7UL << 7)
+#define L3_DISALLOW_MASK (7UL << 7)
+#define L2_DISALLOW_MASK (7UL << 7)
+
#endif /* __X86_32_PAGE_H__ */
#define __PAGE_OFFSET (0xFFFF830000000000)
-/* These may increase in future (phys. bits in particular). */
-#define PADDR_BITS 40
+/* These are page-table limitations. Current CPUs support only 40-bit phys. */
+#define PADDR_BITS 52
#define VADDR_BITS 48
#define PADDR_MASK ((1UL << PADDR_BITS)-1)
#define VADDR_MASK ((1UL << VADDR_BITS)-1)
#endif /* !__ASSEMBLY__ */
/* Strip type from a table entry. */
-#define l1_pgentry_val(_x) ((_x).l1_lo)
-#define l2_pgentry_val(_x) ((_x).l2_lo)
-#define l3_pgentry_val(_x) ((_x).l3_lo)
-#define l4_pgentry_val(_x) ((_x).l4_lo)
+#define l1_pgentry_val(_x) ((_x).l1_lo)
+#define l2_pgentry_val(_x) ((_x).l2_lo)
+#define l3_pgentry_val(_x) ((_x).l3_lo)
+#define l4_pgentry_val(_x) ((_x).l4_lo)
+#define root_pgentry_val(_x) (l4_pgentry_val(_x))
/* Add type to a table entry. */
-#define mk_l1_pgentry(_x) ( (l1_pgentry_t) { (_x) } )
-#define mk_l2_pgentry(_x) ( (l2_pgentry_t) { (_x) } )
-#define mk_l3_pgentry(_x) ( (l3_pgentry_t) { (_x) } )
-#define mk_l4_pgentry(_x) ( (l4_pgentry_t) { (_x) } )
+#define mk_l1_pgentry(_x) ( (l1_pgentry_t) { (_x) } )
+#define mk_l2_pgentry(_x) ( (l2_pgentry_t) { (_x) } )
+#define mk_l3_pgentry(_x) ( (l3_pgentry_t) { (_x) } )
+#define mk_l4_pgentry(_x) ( (l4_pgentry_t) { (_x) } )
+#define mk_root_pgentry(_x) (mk_l4_pgentry(_x))
/* Turn a typed table entry into a physical address. */
-#define l1_pgentry_to_phys(_x) (l1_pgentry_val(_x) & (PADDR_MASK & PAGE_MASK))
-#define l2_pgentry_to_phys(_x) (l2_pgentry_val(_x) & (PADDR_MASK & PAGE_MASK))
-#define l3_pgentry_to_phys(_x) (l3_pgentry_val(_x) & (PADDR_MASK & PAGE_MASK))
-#define l4_pgentry_to_phys(_x) (l4_pgentry_val(_x) & (PADDR_MASK & PAGE_MASK))
+#define l1_pgentry_to_phys(_x) (l1_pgentry_val(_x) & (PADDR_MASK&PAGE_MASK))
+#define l2_pgentry_to_phys(_x) (l2_pgentry_val(_x) & (PADDR_MASK&PAGE_MASK))
+#define l3_pgentry_to_phys(_x) (l3_pgentry_val(_x) & (PADDR_MASK&PAGE_MASK))
+#define l4_pgentry_to_phys(_x) (l4_pgentry_val(_x) & (PADDR_MASK&PAGE_MASK))
+#define root_pgentry_to_phys(_x) (l4_pgentry_to_phys(_x))
/* Turn a typed table entry into a page index. */
-#define l1_pgentry_to_pfn(_x) (l1_pgentry_val(_x) >> PAGE_SHIFT)
-#define l2_pgentry_to_pfn(_x) (l2_pgentry_val(_x) >> PAGE_SHIFT)
-#define l3_pgentry_to_pfn(_x) (l3_pgentry_val(_x) >> PAGE_SHIFT)
-#define l4_pgentry_to_pfn(_x) (l4_pgentry_val(_x) >> PAGE_SHIFT)
+#define l1_pgentry_to_pfn(_x) (l1_pgentry_val(_x) >> PAGE_SHIFT)
+#define l2_pgentry_to_pfn(_x) (l2_pgentry_val(_x) >> PAGE_SHIFT)
+#define l3_pgentry_to_pfn(_x) (l3_pgentry_val(_x) >> PAGE_SHIFT)
+#define l4_pgentry_to_pfn(_x) (l4_pgentry_val(_x) >> PAGE_SHIFT)
+#define root_pgentry_to_pfn(_x) (l4_pgentry_to_pfn(_x))
/* Pagetable walking. */
#define l2_pgentry_to_l1(_x) \
/* Given a virtual address, get an entry offset into a linear page table. */
#define l1_linear_offset(_a) (((_a) & VADDR_MASK) >> PAGE_SHIFT)
+#define PGT_root_page_table PGT_l4_page_table
+
+#define _PAGE_NX (cpu_has_nx ? (1UL<<63) : 0UL)
+
+#define L1_DISALLOW_MASK ((cpu_has_nx?0:(1UL<<63)) | (3UL << 7))
+#define L2_DISALLOW_MASK ((cpu_has_nx?0:(1UL<<63)) | (7UL << 7))
+#define L3_DISALLOW_MASK ((cpu_has_nx?0:(1UL<<63)) | (7UL << 7))
+#define L4_DISALLOW_MASK ((cpu_has_nx?0:(1UL<<63)) | (7UL << 7))
+
#endif /* __X86_64_PAGE_H__ */